home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / lpDaemon SRC / Common Sources / TCPstream.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-14  |  17.2 KB  |  647 lines  |  [TEXT/KAHL]

  1. /************************************************************************
  2.  *                                                                        *
  3.  * TCPStream.C                                                            *
  4.  *                                                                        *
  5.  * Provides a simplified High Level interface to TCP.                    *
  6.  *                                                                        *
  7.  * All routines have a state flag which will be > 0 while the call is     *
  8.  * in progress and <= 0 when completed.  The low-level routines are     *
  9.  * called asynchronously and the high level routine returns.            *
  10.  *                                                                        *
  11.  *                                                                        *
  12.  *  Written by Casper Boon, April, 1992.                                *
  13.  *                                                                        *
  14.  *    © 1992, CorkScrew Computer Technologies.                            *
  15.  *                                                                        *
  16.  ************************************************************************/
  17.  
  18. #include <MacTCPCommonTypes.h>
  19. #include <CvtAddr.h>
  20. #include <TCPPB.h>
  21.  
  22. #include "BackGrounder.H"
  23. #include "TCPStream.H"
  24.  
  25. extern Boolean debugOn;
  26.  
  27. #define kBufferLen        16384
  28. #define kMaxConnections       20
  29. #define kTimeOut           40
  30.  
  31. void TCPSError(StringPtr s, integer e);
  32.  
  33. /************************************************************************/
  34. typedef struct
  35.     {
  36.     TCPiopb            rpb;                /* a Param Block for reading */
  37.     TCPiopb            wpb;                /* a Param Block for writing */
  38.     integer            *rstate;            /* a result code for reading */
  39.     integer            *wstate;            /* a result code for writing */
  40.     integer            *rsize;                /* a size for reading */
  41.     integer            *reof;                /* read at eof (connection closed) */
  42.     ip_addr            remoteHost;
  43.     tcp_port        remotePort;
  44.     ip_addr            localHost;
  45.     tcp_port        localPort;
  46.     Boolean            opened;
  47.     Boolean            termValid;
  48.     integer            refNum;
  49.     StreamPtr        streamPtr;            /* the stream associated with this */
  50.     Word            termReason;
  51.     struct ICMPReport icmpMsg;
  52.     } TCP_;
  53.  
  54.  
  55.     /* opening call back routines */
  56. static void MadeConnection(integer flag, Ptr param);
  57.     /* reading call back routines */
  58. static void ReadDone(integer flag, Ptr param);
  59.     /* writing call back routines */
  60. static void WriteDone(integer flag, Ptr param);
  61.     /* closing call back routines */
  62. static void CloseDone(integer flag, Ptr param);
  63. static void ReleaseDone(integer flag, Ptr param);
  64.  
  65. void WaitForState(integer *state);
  66.  
  67. pascal char *ReturnA5(void) = { 0x2E8D };
  68.  
  69.  
  70. static TCP_ * tcpBlkBuf[kMaxConnections] = {
  71.                             NIL, NIL, NIL, NIL, NIL,
  72.                             NIL, NIL, NIL, NIL, NIL,
  73.                             NIL, NIL, NIL, NIL, NIL,
  74.                             NIL, NIL, NIL, NIL, NIL
  75.                             };
  76. static integer    _tcpRefNum = 0;
  77.  
  78.  
  79. /************************************************************************
  80.  *                                                                        *
  81.  * Initialise local data buffers and open the TCP Driver                *
  82.  *                                                                        *
  83.  ************************************************************************/
  84. OSErr InitTCPS()
  85. {
  86.     integer    i;
  87.     for (i = 0; i < kMaxConnections; i++)
  88.         tcpBlkBuf[i] = NIL;
  89.     return OpenDriver("\p.IPP", &_tcpRefNum);
  90. }
  91.  
  92.  
  93. /************************************************************************
  94.  *                                                                        *
  95.  * Close any connections and dispose of the data buffers                *
  96.  * The TCP driver should not be closed because other applications may    *
  97.  * be using it.  It would return a closeErr error anyway.                *
  98.  *                                                                        *
  99.  ************************************************************************/
  100. void ExitTCPS()
  101. {
  102.     integer    i;
  103.     for (i = 0; i < kMaxConnections; i++)
  104.         {
  105.         if (tcpBlkBuf[i] != NIL)
  106.             {
  107.             TCP_    *tcpBlock = tcpBlkBuf[i];
  108.             TCPiopb *pBlock = &tcpBlock->wpb;
  109.             OSErr    err;
  110.  
  111.             /*** abort the connection ***/
  112.             ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
  113.             pBlock->csCode = TCPAbort;
  114.             pBlock->ioCRefNum = _tcpRefNum;
  115.             pBlock->ioCompletion = NIL;
  116.             pBlock->tcpStream = tcpBlock->streamPtr;
  117.             err = PBControl((ParmBlkPtr)pBlock, FALSE);
  118.  
  119.             /*** release the stream ***/
  120.             ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
  121.             pBlock->csCode = TCPRelease;
  122.             pBlock->ioCRefNum = _tcpRefNum;
  123.             pBlock->tcpStream = tcpBlock->streamPtr;
  124.             pBlock->csParam.create.userDataPtr = NIL;
  125.             err = PBControl((ParmBlkPtr)pBlock, FALSE);
  126.  
  127.             /*** dispose of our memory ***/
  128.             DisposPtr(pBlock->csParam.create.rcvBuff);
  129.             DisposPtr((Ptr)tcpBlock);
  130.             }
  131.         }
  132. }
  133.  
  134.  
  135. /************************************************************************
  136.  *                                                                        *
  137.  * Open a TCP connection. If a remote host name is provided the name     *
  138.  * will first be resolved by a call to the DNR.  The boolean flag         *
  139.  * "passive" detirmines if the connection should be opened now or if we *
  140.  * just listen for attempts to connect on the port.                        *
  141.  *                                                                        *
  142.  ************************************************************************/
  143. OSErr TCPSOpen( integer     *crefnum,
  144.                 char     *remoteHost,
  145.                 Word      localPort,
  146.                 Word      remotePort,
  147.                 Boolean      passive,
  148.                 integer     *ostate)
  149. {
  150.     OSErr        err;
  151.     TCPiopb     *pBlock;
  152.     TCP_        *tcpBlock;
  153.     LongWord    netNum = 0;
  154.     integer        index;
  155.     Ptr            connectionBuffer;
  156.  
  157.     /*** if we have a name, resolve it ***/
  158.     if (remoteHost)
  159.         {
  160.         if ( (err = ConvertStringToAddr(remoteHost, &netNum)) != noErr )
  161.             {
  162.             TCPSError("\pTCPSOpen cannot resolve name", err);
  163.             *ostate = err;
  164.             return err;
  165.             }
  166.         }
  167.  
  168.     /*** allocate a stream record ***/
  169.     tcpBlock = (TCP_ *)NewPtrClear(sizeof(TCP_));
  170.     if ( (err = MemError()) != noErr)
  171.         {
  172.         TCPSError("\pTCPSOpen cannot allocate parm block", err);
  173.         *ostate = err;
  174.         return err;
  175.         }
  176.  
  177.     /*** Allocate stream buffer ***/
  178.     connectionBuffer = NewPtr(kBufferLen);
  179.     if ( (err = MemError()) != noErr)
  180.         {
  181.         TCPSError("\pTCPSOpen cannot allocate rcv buf", err);
  182.         DisposPtr((Ptr)tcpBlock);
  183.         *ostate = err;
  184.         return err;
  185.         }
  186.  
  187.     /*** find a free stream pointer ***/
  188.     for (index = 0; index < kMaxConnections; index++)
  189.         if ( !tcpBlkBuf[index] )
  190.             {
  191.             tcpBlkBuf[index] = tcpBlock;
  192.             *crefnum = (tcpBlock->refNum = (index + 1));
  193.             break;
  194.             }
  195.  
  196.     /*** initialise the stream record ***/
  197.     tcpBlock->remoteHost = netNum;
  198.     tcpBlock->localPort = localPort;
  199.     tcpBlock->remotePort = remotePort;
  200.     tcpBlock->rstate = ostate;
  201.     tcpBlock->opened = FALSE;
  202.     *ostate = 1;
  203.  
  204.     pBlock = &tcpBlock->rpb;
  205.  
  206.     /*** create the stream ***/
  207.     pBlock->csCode = TCPCreate;
  208.     pBlock->ioResult = 1;
  209.     pBlock->ioCRefNum = _tcpRefNum;
  210.     pBlock->ioCompletion = NIL;
  211.     pBlock->ioNamePtr = ReturnA5();
  212.  
  213.     pBlock->csParam.create.rcvBuff = connectionBuffer;
  214.     pBlock->csParam.create.rcvBuffLen = kBufferLen;
  215.     pBlock->csParam.create.notifyProc = NIL;
  216.     pBlock->csParam.create.userDataPtr = NIL;
  217.  
  218.     if ( (err = PBControl((ParmBlkPtr)pBlock, FALSE)) != noErr )
  219.         {
  220.         TCPSError("\pTCPSOpen create stream error", err);
  221.         return err;
  222.         }
  223.  
  224.     /*** save the stream pointer ***/
  225.     tcpBlock->streamPtr = pBlock->tcpStream;
  226.  
  227.     ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
  228.     pBlock->ioResult = 1;
  229.     pBlock->ioCRefNum = _tcpRefNum;
  230.     pBlock->ioCompletion = NIL;
  231.     pBlock->ioNamePtr = ReturnA5();
  232.     pBlock->tcpStream = tcpBlock->streamPtr;
  233.     if (passive)
  234.         {
  235.         pBlock->csCode = TCPPassiveOpen;
  236.         pBlock->csParam.open.ulpTimeoutValue = 0;        /* use default */
  237.         pBlock->csParam.open.commandTimeoutValue = 0;    /* wait forever */
  238.         }
  239.     else
  240.         {
  241.         pBlock->csCode = TCPActiveOpen;
  242.         pBlock->csParam.open.ulpTimeoutValue = kTimeOut;
  243.         pBlock->csParam.open.commandTimeoutValue = kTimeOut;
  244.         }
  245.     pBlock->csParam.open.ulpTimeoutAction = 1;
  246.     pBlock->csParam.open.validityFlags = 0xC0;
  247.     pBlock->csParam.open.remoteHost = tcpBlock->remoteHost;
  248.     pBlock->csParam.open.remotePort = tcpBlock->remotePort;
  249.     pBlock->csParam.open.localPort = tcpBlock->localPort;
  250.     pBlock->csParam.open.tosFlags = 0;
  251.     pBlock->csParam.open.precedence = 0;
  252.     pBlock->csParam.open.dontFrag = 0;
  253.     pBlock->csParam.open.timeToLive = 0;
  254.     pBlock->csParam.open.security = 0;
  255.     pBlock->csParam.open.optionCnt = 0;
  256.     pBlock->csParam.open.userDataPtr = NIL;
  257.  
  258.     /*** Open the connection asynchronously and wait in the background for a result ***/
  259.     if ( (err = PBControl((ParmBlkPtr)pBlock, TRUE)) == noErr )
  260.         Background(&pBlock->ioResult, MadeConnection, (Ptr)tcpBlock);
  261.     else
  262.         MadeConnection(err, (Ptr)tcpBlock);
  263.  
  264.     TCPSError("\pTCPSOpen result", err);
  265.  
  266.     return err;
  267. }
  268.  
  269.  
  270.  
  271. /************************************************************************
  272.  *                                                                        *
  273.  * When the open connection call completes the backgrounder calls this    *
  274.  * routine to save results, and to clean up if it failed                *
  275.  *                                                                        *
  276.  ************************************************************************/
  277. static void MadeConnection(integer flag, Ptr param)
  278. {
  279.     TCP_    *tcpBlock = (TCP_*)param;
  280.     TCPiopb *pBlock = &tcpBlock->rpb;
  281.     OSErr    err;
  282.  
  283.     tcpBlock->remoteHost = pBlock->csParam.open.remoteHost;
  284.     tcpBlock->remotePort = pBlock->csParam.open.remotePort;
  285.     tcpBlock->localHost = pBlock->csParam.open.localHost;
  286.     tcpBlock->localPort = pBlock->csParam.open.localPort;
  287.  
  288.     if (!flag)
  289.         tcpBlock->opened = TRUE;
  290.     else
  291.         {    /*** bummer, close it up ***/
  292.         TCPSClose(tcpBlock->refNum, &err);
  293.         WaitForState(&err);
  294.         }
  295.  
  296.     *(tcpBlock->rstate) = flag;
  297. }
  298.  
  299.  
  300.  
  301. /************************************************************************
  302.  *                                                                        *
  303.  *                                                                        *
  304.  ************************************************************************/
  305. OSErr TCPSRead(integer crefnum, Ptr data, integer *size,
  306.                                         integer *eof, integer *rstate)
  307. {
  308.     TCP_    *tcpBlock;
  309.     TCPiopb *pBlock;
  310.     OSErr    err;
  311.  
  312.     if ( crefnum <= 0 || crefnum > kMaxConnections || !tcpBlkBuf[crefnum-1] )
  313.         {
  314.         *rstate = rfNumErr;
  315.         return rfNumErr;
  316.         }
  317.  
  318.     tcpBlock = tcpBlkBuf[crefnum-1];
  319.  
  320.     if ( !tcpBlock->opened )
  321.         {
  322.         *eof = TRUE;
  323.         *rstate = notOpenErr;
  324.         return notOpenErr;
  325.         }
  326.  
  327.     if (*size <= 0)    /* nothing to do */
  328.         {
  329.         *rstate = noErr;
  330.         return noErr;
  331.         }
  332.  
  333.     pBlock = &tcpBlock->rpb;
  334.  
  335.     tcpBlock->rsize = size;
  336.     tcpBlock->rstate = rstate;
  337.     tcpBlock->reof = eof;
  338.     *rstate = 1;
  339.     *eof = FALSE;
  340.  
  341.     ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
  342.     pBlock->csCode = TCPRcv;
  343.     pBlock->ioResult = 1;
  344.     pBlock->ioCRefNum = _tcpRefNum;
  345.     pBlock->ioCompletion = NIL;
  346.     pBlock->ioNamePtr = ReturnA5();
  347.     pBlock->tcpStream = tcpBlock->streamPtr;
  348.     pBlock->csParam.receive.commandTimeoutValue = kTimeOut;
  349.     pBlock->csParam.receive.rcvBuff = data;
  350.     pBlock->csParam.receive.rcvBuffLen = *size;
  351.     pBlock->csParam.receive.userDataPtr = NIL;
  352.  
  353.     if ( ! (err = PBControl((ParmBlkPtr)pBlock, TRUE)) )
  354.         Background(&pBlock->ioResult, ReadDone, (Ptr)tcpBlock);
  355.     else
  356.         {
  357.         pBlock->csParam.receive.rcvBuffLen = 0;
  358.         ReadDone(err, (Ptr)tcpBlock);
  359.         }
  360.  
  361.     TCPSError("\pTCPSRead result", err);
  362.  
  363.     return err;
  364. }
  365.  
  366. /************************************************************************
  367.  *                                                                        *
  368.  *                                                                        *
  369.  ************************************************************************/
  370. static
  371. void ReadDone(integer flag, Ptr param)
  372. {
  373.     TCP_    *tcpBlock = (TCP_*)param;
  374.     TCPiopb *pBlock = &tcpBlock->rpb;
  375.  
  376.     TCPSError("\pTCPSRead Done result", flag);
  377.  
  378.     if (flag == connectionClosing) *(tcpBlock->rsize) = 0;
  379.     else *(tcpBlock->rsize) = pBlock->csParam.receive.rcvBuffLen;
  380.     *(tcpBlock->rstate) = flag;
  381.     *(tcpBlock->reof) = (flag == connectionClosing ||
  382.                          flag == connectionTerminated);
  383. }
  384.  
  385. /************************************************************************
  386.  *                                                                        *
  387.  *                                                                        *
  388.  ************************************************************************/
  389. OSErr TCPSWrite(integer crefnum, Ptr data, integer size, integer *wstate)
  390. {
  391.     TCP_    *tcpBlock;
  392.     TCPiopb *pBlock;
  393.     struct wdsEntry *theWDS;
  394.     OSErr    err;
  395.  
  396.     if ( crefnum <= 0 || crefnum > kMaxConnections || !tcpBlkBuf[crefnum-1] )
  397.         {
  398.         *wstate = rfNumErr;
  399.         return rfNumErr;
  400.         }
  401.  
  402.     tcpBlock = tcpBlkBuf[crefnum-1];
  403.  
  404.     if ( !tcpBlock->opened )
  405.         {
  406.         *wstate = notOpenErr;
  407.         return notOpenErr;
  408.         }
  409.  
  410.     if (size <= 0)    /* nothing to do */
  411.         {
  412.         *wstate = noErr;
  413.         return noErr;
  414.         }
  415.  
  416.     pBlock = &tcpBlock->wpb;
  417.  
  418.     tcpBlock->wstate = wstate;
  419.     *wstate = 1;
  420.  
  421.     theWDS = (wdsEntry *)NewPtr( (2*sizeof(wdsEntry)) );
  422.     if ( (err = MemError()) != noErr)
  423.         {
  424.         TCPSError("\pTCPSWrite cannot allocate WDS", err);
  425.         *wstate = err;
  426.         return err;
  427.         }
  428.  
  429.     theWDS[0].length = size;
  430.     theWDS[0].ptr = data;
  431.     theWDS[1].length = 0;
  432.     theWDS[1].ptr = 0;
  433.  
  434.     ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
  435.     pBlock->csCode = TCPSend;
  436.     pBlock->ioResult = 1;
  437.     pBlock->ioCRefNum = _tcpRefNum;
  438.     pBlock->ioCompletion = NIL;
  439.     pBlock->ioNamePtr = ReturnA5();
  440.     pBlock->tcpStream = tcpBlock->streamPtr;
  441.     pBlock->csParam.send.ulpTimeoutValue = kTimeOut;
  442.     pBlock->csParam.send.ulpTimeoutAction = 1;
  443.     pBlock->csParam.send.validityFlags = 0xC0;
  444.     pBlock->csParam.send.pushFlag = FALSE;
  445.     pBlock->csParam.send.urgentFlag = FALSE;
  446.     pBlock->csParam.send.wdsPtr = (Ptr)theWDS;
  447.     pBlock->csParam.send.userDataPtr = NIL;
  448.  
  449.     if ( ! (err = PBControl((ParmBlkPtr)pBlock, TRUE)) )
  450.         Background(&pBlock->ioResult, WriteDone, (Ptr)tcpBlock);
  451.     else
  452.         WriteDone(err, (Ptr)tcpBlock);
  453.  
  454.     TCPSError("\pTCPSWrite result", err);
  455.  
  456.     return err;
  457. }
  458.  
  459.  
  460. /************************************************************************
  461.  *                                                                        *
  462.  *                                                                        *
  463.  ************************************************************************/
  464. static void WriteDone(integer flag, Ptr param)
  465. {
  466.     TCP_    *tcpBlock = (TCP_*)param;
  467.     TCPiopb *pBlock = &tcpBlock->wpb;
  468.  
  469.     TCPSError("\pTCPSWrite Done result", flag);
  470.  
  471.     *(tcpBlock->wstate) = flag;
  472.     DisposPtr((Ptr)pBlock->csParam.send.wdsPtr);
  473. }
  474.  
  475. /************************************************************************
  476.  *                                                                        *
  477.  *                                                                        *
  478.  ************************************************************************/
  479. OSErr TCPSClose(integer crefnum, integer *cstate)
  480. {
  481.     TCP_    *tcpBlock;
  482.     TCPiopb *pBlock;
  483.     OSErr    err = -23008;    /* connection Doesnt Exist */
  484.  
  485.     if ( crefnum <= 0 || crefnum > kMaxConnections || !tcpBlkBuf[crefnum-1] )
  486.         {
  487.         *cstate = rfNumErr;
  488.         return rfNumErr;
  489.         }
  490.  
  491.  
  492.     tcpBlock = tcpBlkBuf[crefnum-1];
  493.     tcpBlkBuf[crefnum-1] = NIL;    /* free this entry */
  494.  
  495.     *cstate = 1;
  496.  
  497.     /* first kill any pending IO requests */
  498.     if (tcpBlock->opened)
  499.         {
  500.         tcpBlock->opened = FALSE;    /* we are closing */
  501.     
  502.         if (tcpBlock->wpb.ioResult > 0)
  503.             PBKillIO((ParmBlkPtr)&tcpBlock->wpb, FALSE);
  504.         if (tcpBlock->wpb.ioResult > 0) tcpBlock->wpb.ioResult=-1;
  505.         RunBackground();
  506.         if (tcpBlock->rpb.ioResult > 0)
  507.             PBKillIO((ParmBlkPtr)&tcpBlock->rpb, FALSE);
  508.         if (tcpBlock->rpb.ioResult > 0) tcpBlock->rpb.ioResult=-1;
  509.         RunBackground();
  510.         }
  511.  
  512.     tcpBlock->wstate = cstate;
  513.  
  514.     pBlock = &tcpBlock->wpb;
  515.  
  516.     ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
  517.     pBlock->csCode = TCPClose;
  518.     pBlock->ioResult = 1;
  519.     pBlock->ioCRefNum = _tcpRefNum;
  520.     pBlock->ioCompletion = NIL;
  521.     pBlock->ioNamePtr = ReturnA5();
  522.     pBlock->tcpStream = tcpBlock->streamPtr;
  523.     pBlock->csParam.close.ulpTimeoutValue = kTimeOut;
  524.     pBlock->csParam.close.ulpTimeoutAction = 1;
  525.     pBlock->csParam.close.validityFlags = 0xC0;
  526.     pBlock->csParam.close.userDataPtr = NIL;
  527.  
  528.     if ( ! (err = PBControl((ParmBlkPtr)pBlock, TRUE)) )
  529.         Background(&pBlock->ioResult, CloseDone, (Ptr)tcpBlock);
  530.     else
  531.         CloseDone(err, (Ptr)tcpBlock);
  532.  
  533.     TCPSError("\pTCPSClose result", err);
  534.  
  535.     return err;
  536. }
  537.  
  538. /************************************************************************
  539.  *                                                                        *
  540.  *                                                                        *
  541.  ************************************************************************/
  542. static void CloseDone(integer flag, Ptr param)
  543. {
  544.     TCP_    *tcpBlock = (TCP_*)param;
  545.     TCPiopb *pBlock = &tcpBlock->wpb;
  546.     OSErr    err;
  547.  
  548.     if (flag)
  549.         {
  550.         ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
  551.         pBlock->csCode = TCPAbort;
  552.         pBlock->ioCRefNum = _tcpRefNum;
  553.         pBlock->ioCompletion = NIL;
  554.         pBlock->tcpStream = tcpBlock->streamPtr;
  555.         err = PBControl((ParmBlkPtr)pBlock, FALSE);
  556.         }
  557.  
  558.     ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
  559.     pBlock->csCode = TCPRelease;
  560.     pBlock->ioCRefNum = _tcpRefNum;
  561.     pBlock->tcpStream = tcpBlock->streamPtr;
  562.     pBlock->csParam.create.userDataPtr = NIL;
  563.     err = PBControl((ParmBlkPtr)pBlock, FALSE);
  564.  
  565.     TCPSError("\pTCPSClose Done result", err);
  566.  
  567.     *(tcpBlock->wstate) = err;
  568.     DisposPtr(pBlock->csParam.create.rcvBuff);
  569.     DisposPtr((Ptr)tcpBlock);
  570. }
  571.  
  572.  
  573.  
  574. /************************************************************************
  575.  *                                                                        *
  576.  *                                                                        *
  577.  ************************************************************************/
  578. OSErr TCPSConnInfo(integer crefnum,
  579.                     LongWord *localHost, LongWord *remoteHost,
  580.                         Word *localPort,      Word *remotePort)
  581. {
  582.     TCP_    *tcpBlock;
  583.  
  584.     if ( crefnum <= 0 || crefnum > kMaxConnections || !tcpBlkBuf[crefnum-1] )
  585.         return badUnitErr;
  586.  
  587.     tcpBlock = tcpBlkBuf[crefnum-1];
  588.  
  589.     *localHost  = tcpBlock->localHost;
  590.     *remoteHost = tcpBlock->remoteHost;
  591.     *localPort  = tcpBlock->localPort;
  592.     *remotePort = tcpBlock->remotePort;
  593.  
  594.     return 0;
  595. }
  596.  
  597. /************************************************************************
  598.  *                                                                        *
  599.  * This was for the future (which never came)                            *
  600.  *                                                                        *
  601.  ************************************************************************/
  602. pascal void StreamNotifyProc (
  603.         StreamPtr tcpStream,
  604.         Word eventCode,
  605.         Ptr userDataPtr,
  606.         Word terminReason,
  607.         struct ICMPReport *icmpMsg);
  608.  
  609. pascal void StreamNotifyProc (
  610.         StreamPtr tcpStream,
  611.         Word eventCode,
  612.         Ptr userDataPtr,
  613.         Word terminReason,
  614.         struct ICMPReport *icmpMsg)
  615. {
  616. }
  617.  
  618.  
  619. /************************************************************************
  620.  *                                                                        *
  621.  *  Display an error message when something goes wrong.                  *
  622.  *  We only do this if we are debugging, otherwise the error should be    *
  623.  *  picked up and display by whatever called the TCPStream routine that    *
  624.  *  caused the error.                                                    *
  625.  *                                                                        *
  626.  ************************************************************************/
  627. void TCPSError(StringPtr s, integer e)
  628. {
  629.     Str255        str;
  630.     extern integer stdlog;
  631.  
  632.     if (e == noErr) return;                        /* nothing to report */
  633.  
  634.     if (!debugOn) return;    /* actually not interested at this stage */
  635.  
  636.     if (stdlog)
  637.         {
  638.         log_printf("%p %d\n", s, e);
  639.         return;
  640.         }
  641.  
  642.     psprintf(str, "TCP Stream Error\015\015%p\015 errNo %d", s, e);
  643.     ParamText(str, NIL, NIL, NIL);    /* tell dialog manager     */
  644.  
  645.     InternalAlert();
  646. }
  647.